package br.com.hs.nfe.common.util;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.regex.Pattern;

/**
 * Classe responsavel por tratar data e hora.
 * @author Ranlive Hrysyk
 */
public class DateHelper {

    /**
     * Pattern Data e Hora.
     */
    public static final Pattern PATTERN_DATE_TIME_FORMAT = Pattern.compile("\\s*(0[1-9]|[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012]|[1-9])/(19|20)\\d{2} ([0-1][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\\s*");
    /**
     * Pattern Data.
     */
    public static final Pattern PATTERN_DATE_FORMAT = Pattern.compile("\\s*(0[1-9]|[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012]|[1-9])/(19|20)\\d{2}\\s*");
    /**
     * Pattern Hora.
     */
    public static final Pattern PATTERN_TIME_FORMAT = Pattern.compile("\\s*([0-1][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\\s*");
    /**
     * Formato: dd/MM/yyyy
     */
    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
    /**
     * Formato: HH:mm:ss
     */
    public static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
    /**
     * Formato: dd/MM/yyyy HH:mm:ss
     */
    public static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    /**
     * Formato: dd/MM/yyyy HH:mm
     */
    public static final SimpleDateFormat DATE_HOUR_MINUTE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm");
    /**
     * Formato: dd/MM/yyyy HH:mm
     */
    public static final SimpleDateFormat SIMPLE_DATE_TIME_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm");
    /**
     * Formato: dd/MM/yyyy HH:mm:ss SSS
     */
    public static final SimpleDateFormat DATE_TIME_MILLISECOND_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss SSS");
    /**
     * Formato: yyyyMMddHHmm
     */
    public static final SimpleDateFormat DATE_TIME_FORMAT_BACKUP = new SimpleDateFormat("yyyyMMddHHmm");
    /**
     * Formato: yyyyMMdd-HHmm
     */
    public static final SimpleDateFormat DATE_TIME_FORMAT_EXPORT = new SimpleDateFormat("yyyyMMdd-HHmm");
    /**
     * Formato: yyyyMMdd
     */
    public static final SimpleDateFormat DATE_FORMAT_BACKUP = new SimpleDateFormat("yyyyMMdd");
    /**
     * Formato: yyyy-MM-dd
     */
    public static final SimpleDateFormat DATE_XML_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    /**
     * Formato: yyyy-MM-dd'T'HH:mm:ss
     */
    public static final SimpleDateFormat DATE_TIME_XML_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    /**
     * Formato: ddMMyyyy-HHmmss
     */
    public static final SimpleDateFormat DATE_NOME_ARQUIVO_FORMAT = new SimpleDateFormat("ddMMyyyy-HHmmss");
    /**
     * Formato: MM/yy
     */
    public static final SimpleDateFormat DATE_MONTH_DECADE_FORMAT = new SimpleDateFormat("MM/yy");
    /**
     * Formato: MM
     */
    public static final SimpleDateFormat DATE_MONTH_FORMAT = new SimpleDateFormat("MM");
    /**
     * Formato: yy
     */
    public static final SimpleDateFormat DATE_YEAR_FORMAT = new SimpleDateFormat("yy");
    /**
     * Formato: yyyy
     */
    public static final SimpleDateFormat DATE_YEAR_X4_FORMAT = new SimpleDateFormat("yyyy");

    static {
        DATE_FORMAT.setLenient(false);
        DATE_TIME_FORMAT.setLenient(false);
        TIME_FORMAT.setLenient(false);
        DATE_TIME_FORMAT_BACKUP.setLenient(false);
        SIMPLE_DATE_TIME_FORMAT.setLenient(false);
        DATE_FORMAT_BACKUP.setLenient(false);
        DATE_HOUR_MINUTE_FORMAT.setLenient(false);
        DATE_TIME_MILLISECOND_FORMAT.setLenient(false);
        DATE_TIME_FORMAT_EXPORT.setLenient(false);
        DATE_TIME_FORMAT_EXPORT.setLenient(false);
        DATE_XML_FORMAT.setLenient(false);
        DATE_TIME_XML_FORMAT.setLenient(false);
        DATE_NOME_ARQUIVO_FORMAT.setLenient(false);
    }

    /**
     * Obtém Date de uma String.
     */
    public static Date getDate(String strDate) {
        return getDate(strDate, 0, 0, 0, 0);
    }

    /**
     * Gera Date pela data, hora, minuto, segundo e milisegundo.
     */
    public static Date getDate(String strDate, int hour, int minute, int second, int millisecond) {
        try {
            GregorianCalendar gc = new GregorianCalendar();
            gc.setTime(DATE_FORMAT.parse(strDate));
            gc.set(11, hour);
            gc.set(12, minute);
            gc.set(13, second);
            gc.set(14, millisecond);
            return gc.getTime();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Valida um formato de data.
     */
    public static boolean isValidFormatDate(Pattern pattern, String strDate) {
        return pattern.matcher(strDate).matches();
    }

    /**
     * Obtém data formatada.
     */
    public static Date getDateTime(String strDate, SimpleDateFormat simpleDateFormat) {
        try {
            GregorianCalendar gc = new GregorianCalendar();
            gc.setTime(simpleDateFormat.parse(strDate));
            return gc.getTime();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Obtém Date formatado.
     */
    public static Date getDate(String strDate, SimpleDateFormat simpleDateFormat) {
        try {
            return simpleDateFormat.parse(strDate);
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Formatar data e hora.
     */
    public static String formatarDataHora(Date date, SimpleDateFormat simpleDateFormat) {
        if (date == null) {
            return null;
        }
        return simpleDateFormat.format(date);
    }

    /**
     * Formatar data.
     */
    public static String formatarData(Date d) {
        if (d == null) {
            return null;
        }
        return DATE_FORMAT.format(d);
    }

    /**
     * Formatar Hora.
     */
    public static String formatarHora(Date date) {
        if (date == null) {
            return null;
        }
        return TIME_FORMAT.format(date);
    }

    /**
     * Obtém um Date pelo Calendar.
     */
    public static Date getDateFromCalendar(Calendar cal) {
        if (cal == null) {
            return null;
        }
        String myDateString = completaComZeros(cal.get(5), 2) + "/"
                + completaComZeros(cal.get(2) + 1, 2) + "/"
                + completaComZeros(cal.get(1), 4) + " "
                + completaComZeros(cal.get(11), 2) + ":"
                + completaComZeros(cal.get(12), 2) + ":"
                + completaComZeros(cal.get(13), 2) + " "
                + completaComZeros(cal.get(14), 3);

        return getDateTime(myDateString, DATE_TIME_MILLISECOND_FORMAT);
    }

    /**
     * Completa com zeros à esquerda.
     */
    private static String completaComZeros(int value, int quantCasas) {
        String valueStr = "" + value;
        int numZeros = quantCasas - valueStr.length();
        while (numZeros > 0) {
            valueStr = "0" + valueStr;
            numZeros--;
        }
        return valueStr;
    }

    /**
     * Obtém um Calendar pelo Date.
     */
    public static Calendar getCalendar(Date date) {
        GregorianCalendar dateCalendar = new GregorianCalendar();
        dateCalendar.setTime(date);
        GregorianCalendar formattedCalendar = new GregorianCalendar(dateCalendar.get(1), dateCalendar.get(2), dateCalendar.get(5));
        return formattedCalendar;
    }

    /**
     * Obter número de dias entre duas datas.
     */
    public static long getDaysBetweenDates(Date dAfter, Date dBefore) {
        return (dAfter.getTime() - dBefore.getTime()) / 86400000L;
    }
}
